package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"github.com/yourusername/gox/pkg/generator"
	"github.com/yourusername/gox/pkg/parser"
)

var (
	inputFile  string
	outputFile string
	inputDir   string
	outputDir  string
	verbose    bool
)

var rootCmd = &cobra.Command{
	Use:   "goxc",
	Short: "GoX 编译器 - 将 .gox 文件编译为标准 Go 代码",
	Long: `GoX 编译器用于将包含嵌入式 SQL 的 .gox 文件编译为标准的 Go 代码。
支持类似 JSX 的语法，可以在 Go 代码中直接嵌入 SQL 查询。

示例:
  goxc -i example.gox -o example.go
  goxc -dir ./src -out ./gen`,
	Run: compile,
}

func init() {
	rootCmd.Flags().StringVarP(&inputFile, "input", "i", "", "输入的 .gox 文件")
	rootCmd.Flags().StringVarP(&outputFile, "output", "o", "", "输出的 .go 文件")
	rootCmd.Flags().StringVarP(&inputDir, "dir", "d", "", "输入目录（编译目录中所有 .gox 文件）")
	rootCmd.Flags().StringVarP(&outputDir, "out", "", "", "输出目录")
	rootCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "详细输出")
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "错误: %v\n", err)
		os.Exit(1)
	}
}

func compile(cmd *cobra.Command, args []string) {
	if inputFile != "" {
		// 编译单个文件
		if err := compileFile(inputFile, outputFile); err != nil {
			fmt.Fprintf(os.Stderr, "编译失败: %v\n", err)
			os.Exit(1)
		}
		if verbose {
			fmt.Printf("成功编译: %s -> %s\n", inputFile, outputFile)
		}
	} else if inputDir != "" {
		// 编译目录
		if err := compileDirectory(inputDir, outputDir); err != nil {
			fmt.Fprintf(os.Stderr, "编译目录失败: %v\n", err)
			os.Exit(1)
		}
		if verbose {
			fmt.Printf("成功编译目录: %s -> %s\n", inputDir, outputDir)
		}
	} else {
		fmt.Fprintf(os.Stderr, "请指定输入文件 (-i) 或输入目录 (-d)\n")
		os.Exit(1)
	}
}

func compileFile(input, output string) error {
	// 读取输入文件
	src, err := ioutil.ReadFile(input)
	if err != nil {
		return fmt.Errorf("读取文件失败: %w", err)
	}

	// 解析文件
	p := parser.NewParser()
	goxFile, err := p.ParseFile(input, src)
	if err != nil {
		return fmt.Errorf("解析文件失败: %w", err)
	}

	// 生成代码
	gen := generator.NewGenerator(p.GetFileSet())
	generated, err := gen.Generate(goxFile)
	if err != nil {
		return fmt.Errorf("生成代码失败: %w", err)
	}

	// 确定输出文件名
	if output == "" {
		output = strings.TrimSuffix(input, filepath.Ext(input)) + ".go"
	}

	// 写入输出文件
	err = ioutil.WriteFile(output, generated, 0644)
	if err != nil {
		return fmt.Errorf("写入文件失败: %w", err)
	}

	return nil
}

func compileDirectory(inputDir, outputDir string) error {
	// 确保输出目录存在
	if outputDir == "" {
		outputDir = inputDir
	}

	err := os.MkdirAll(outputDir, 0755)
	if err != nil {
		return fmt.Errorf("创建输出目录失败: %w", err)
	}

	// 遍历输入目录
	return filepath.Walk(inputDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 只处理 .gox 文件
		if !strings.HasSuffix(path, ".gox") {
			return nil
		}

		// 计算输出文件路径
		relPath, err := filepath.Rel(inputDir, path)
		if err != nil {
			return err
		}

		outputPath := filepath.Join(outputDir, strings.TrimSuffix(relPath, ".gox")+".go")

		// 确保输出文件的目录存在
		outputFileDir := filepath.Dir(outputPath)
		err = os.MkdirAll(outputFileDir, 0755)
		if err != nil {
			return fmt.Errorf("创建输出文件目录失败: %w", err)
		}

		// 编译文件
		err = compileFile(path, outputPath)
		if err != nil {
			return fmt.Errorf("编译 %s 失败: %w", path, err)
		}

		if verbose {
			fmt.Printf("编译: %s -> %s\n", path, outputPath)
		}

		return nil
	})
}
